/*
    Project Milestone 3
    by Lorenzo Miori [Lorenzo.Miori@stud-inf.unibz.it,
    Matteo Angriman [Matteo.Angriman@stud-inf.unibz.it],
    Nick Preda [Nicolae.Preda@stud-inf.unibz.it]
*/

package DB;

import java.sql.*;
import java.util.Arrays;
import java.util.concurrent.Semaphore;
import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

/**
 * Connection manager. Stores and asks credentials and initiates a DB
 * connection. Returns a valid connection OR null in case of wrong credentials /
 * aborted login
 */
public class DatabaseLogin implements ActionListener, WindowListener {

    /* General stuff */
    public static final Dimension WINDOW_SIZE = new Dimension(600, 150);
    private final int CONNECTION_TIMEOUT = 4;
    private Semaphore connectionSemaphore;
    private static Connection dbConnection;
    private boolean exitRequested = false;
    
    /* GUI stuff */
    private JFrame connectionWindow;
    private JPanel windowPanel;
    private JPanel buttonsPanel;
    private JPanel optionsPanel;
    private JButton connectButton;
    private JButton exitButton;
    private JPasswordField passwordField;
    private JTextField userField;
    private JTextField urlField;
    
    private String url = "jdbc:postgresql://alcor.inf.unibz.it:5432/ds_group3";
    private String user = "ds_group3";
    //private String url = "jdbc:postgresql://maiorsserver.zapto.org:5432/postgres";
    //private String user = "postgres";
    /* Contains default password! Not very secure here indeed... */
    private String defaultPassword = "Phie5pia";

    public DatabaseLogin(String title) {

        connectionSemaphore = new Semaphore(0);
        connectionWindow = new JFrame(title);
        buttonsPanel = new JPanel();
        optionsPanel = new JPanel();
        windowPanel = (JPanel) connectionWindow.getContentPane();
        windowPanel.setLayout(new BorderLayout());
        connectButton = new JButton("Connect!");
        connectButton.setActionCommand("connectRequest");
        connectButton.addActionListener(this);
        KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true);
        connectButton.registerKeyboardAction(this, "connectRequest", stroke, JComponent.WHEN_IN_FOCUSED_WINDOW);
        exitButton = new JButton("Exit");
        exitButton.setActionCommand("exitLogin");
        exitButton.addActionListener(this);
        userField = new JTextField(user);
        urlField = new JTextField(url);

        passwordField = new JPasswordField(defaultPassword);
        passwordField.setActionCommand("pwdfield");
        passwordField.addActionListener(this);

        optionsPanel.setLayout(new GridLayout(0, 2));
        optionsPanel.add(new JLabel("DB URL"));
        optionsPanel.add(urlField);
        optionsPanel.add(new JLabel("Username"));
        optionsPanel.add(userField);
        optionsPanel.add(new JLabel("Password"));
        optionsPanel.add(passwordField);
        buttonsPanel.add(exitButton);
        buttonsPanel.add(connectButton);

        connectionWindow.setPreferredSize(WINDOW_SIZE);
        connectionWindow.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        connectionWindow.setResizable(false);
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        connectionWindow.setLocation((screenSize.width - WINDOW_SIZE.width) / 2,
                                 (screenSize.height - WINDOW_SIZE.height) / 2);

        optionsPanel.setLayout(new GridLayout(0, 2));
    }
    
    //Not very safe and clean to keep such an object static...
    public static Connection getLastConnection() {
        return dbConnection;
    }

    public void showFrame(boolean enable, boolean blocking) {
        windowPanel.removeAll();
        windowPanel.add(buttonsPanel, BorderLayout.SOUTH);
        windowPanel.add(optionsPanel, BorderLayout.CENTER);
        connectionWindow.pack();
        connectionWindow.setVisible(enable);
        if (blocking) {
            try {
                connectionSemaphore.acquire();
            } catch (InterruptedException e) {
                System.out.println(e.getMessage());
            }
        }
    }

    public Connection dbConnect() {

        /* Dirty hack for the exit button
         * Don't try this at home
         */
        if (exitRequested) {
            return null;
        }

        try {
            char[] password = passwordField.getPassword();
            Class.forName("org.postgresql.Driver");
            /* Wait a little... */
            DriverManager.setLoginTimeout(CONNECTION_TIMEOUT);
            dbConnection = DriverManager.getConnection(urlField.getText(), userField.getText(), new String(password));
            /* Security helper: get rid of residual password in memory! */
            Arrays.fill(password, '0');
            return dbConnection;
        } catch (SQLException e) {
            JOptionPane.showMessageDialog(connectionWindow,
                    "Error connecting to the database: " + e.getMessage(),
                    "Connection Error :(", JOptionPane.ERROR_MESSAGE);
        } catch (Exception e) {
            JOptionPane.showMessageDialog(connectionWindow,
                    "Unknown error during connection: " + e.getMessage(),
                    "Unknown Error :(", JOptionPane.ERROR_MESSAGE);
        }
        return null;
    }

    public Connection getConnection() {
        return dbConnection;
    }

    public Connection closeConnection() {
        if (dbConnection != null) {
            try {
                dbConnection.close();
            } catch (SQLException e) {
                System.out.println("Disconnection error! "
                        + e.getMessage());
            }
        }
        return dbConnection;
    }

    @Override
    public void windowActivated(WindowEvent arg0) {
    }

    @Override
    public void windowClosed(WindowEvent arg0) {
    }

    @Override
    public void windowClosing(WindowEvent arg0) {
    }

    @Override
    public void windowDeactivated(WindowEvent arg0) {
    }

    @Override
    public void windowDeiconified(WindowEvent arg0) {
    }

    @Override
    public void windowIconified(WindowEvent arg0) {
    }

    @Override
    public void windowOpened(WindowEvent arg0) {
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        String cmd = arg0.getActionCommand();

        if (cmd.equals("connectRequest")) {
            /* Releasing the semaphore will unblock showFrame if set to be blocking */
            if (connectionSemaphore != null) {
                connectionSemaphore.release();
                connectionWindow.setVisible(false);
            }
        }
        if (cmd.equals("exitLogin")) {
            exitRequested = true;
            if (connectionSemaphore != null) {
                connectionSemaphore.release();
                closeConnection();
                System.exit(0);
            }
        }

    }
}